<?php

namespace plugin\thinkphp\traits;
use plugin\thinkphp\Admin;
use think\db\Query;
use think\facade\Db;

/**
 * @method $this offDataAuth() 关闭数据权限
 */
trait DataPermissions
{
    //全部数据权限
    private $FULL_DATA_RIGHTS = 0;
    //自定义数据权限
    private $CUSTOM_DATA_PERMISSIONS = 1;
    //本部门及以下数据权限
    private $THIS_DEPARTMENT_AND_THE_FOLLOWING_DATA_PERMISSIONS = 2;
    //本部门数据权限
    private $DATA_PERMISSIONS_FOR_THIS_DEPARTMENT = 3;
    //本人数据权限
    private $PERSONAL_DATA_RIGHTS = 4;

    /**
     * 关闭数据权限
     * @param Query $query
     * @return \think\db\BaseQuery
     */
    public function scopeOffDataAuth(Query $query)
    {
        return $query->getModel()->db(['dataAuth']);
    }

    /**
     * 数据权限字段
     * @param Query $query
     * @return \think\db\BaseQuery
     */
    public function scopeDataAuth($query)
    {
        $adminId = Admin::id();
        if ($adminId && plugin()->thinkphp->config('admin_auth_id') != $adminId && count($this->dataAuth) > 0) {

            $role_user_table = plugin()->thinkphp->config('database.role_user_table');
            $role_table = plugin()->thinkphp->config('database.role_table');
            $role = Db::connect($this->getConnection())->table($role_table)
                ->fieldRaw($role_table . '.id,data_type')
                ->where($role_user_table . '.user_id', $adminId)
                ->join($role_user_table, $role_user_table . '.role_id = '.$role_table . '.id')
                ->order('data_type')
                ->cache(1)
                ->find();

            $query->where(function (Query $query) use ($role, $adminId) {
                $table = $this->getTable();
                $user_table = plugin()->thinkphp->config('database.user_table');
                switch ($role['data_type']) {
                    case $this->CUSTOM_DATA_PERMISSIONS:

                        $role_department_table = plugin()->thinkphp->config('database.role_department_table');
                        $query->where(function ($q) use ($table, $query, $user_table, $role_department_table, $role) {
                            $this->eachDataAuth(function ($field, $adminField) use ($table, $q, $user_table, $role_department_table, $role) {
                                $db = DB::connect($this->getConnection())->table($user_table)
                                    ->fieldRaw($user_table . '.' . $adminField)
                                    ->whereNull($user_table.'.delete_time')
                                    ->join($role_department_table, $role_department_table . '.department_id = '.$user_table . '.department_id')
                                    ->where($role_department_table . '.role_id', $role['id']);
                                $q->whereRaw($table . '.' . $field . ' IN (' . $db->buildSql() . ')');
                            });
                        })->whereOr(function ($q) use ($table) {
                            $this->eachDataAuth(function ($field, $adminField) use ($table, $q) {
                                $q->where($table . '.' . $field, Admin::user()->$adminField);
                            });
                        });
                        break;
                    case $this->THIS_DEPARTMENT_AND_THE_FOLLOWING_DATA_PERMISSIONS:

                        $department_id = Admin::user()->department_id;
                        $department_table = plugin()->thinkphp->config('database.department_table');
                        $this->eachDataAuth(function ($field, $adminField) use ($table, $query, $department_id, $user_table, $department_table) {
                            $db = DB::connect($this->getConnection())->table($user_table)
                                ->fieldRaw($user_table . '.' . $adminField)
                                ->whereNull($user_table.'.delete_time')
                                ->join($department_table, $department_table . '.id = '. $user_table . '.department_id')
                                ->whereRaw("FIND_IN_SET({$department_id},{$department_table}.path)");
                            $query->whereRaw($table . '.' . $field . ' IN (' . $db->buildSql() . ')');
                        });
                        break;
                    case $this->DATA_PERMISSIONS_FOR_THIS_DEPARTMENT:

                        $department_id = Admin::user()->department_id;
                        $this->eachDataAuth(function ($field, $adminField) use ($table, $query, $department_id, $user_table) {
                            $db = DB::connect($this->getConnection())->table($user_table)
                                ->fieldRaw($user_table . '.' . $adminField)
                                ->whereNull($user_table.'.delete_time')
                                ->where('department_id', $department_id);
                            $query->whereRaw($table . '.' . $field . ' IN (' . $db->buildSql() . ')');
                        });
                        break;
                    case $this->PERSONAL_DATA_RIGHTS:
                        $this->eachDataAuth(function ($field, $adminField) use ($table, $query) {
                            $query->where($table . '.' . $field, Admin::user()->$adminField);
                        });
                        break;
                }
            });
        }
    }

    private function eachDataAuth(\Closure $closure)
    {
        foreach ($this->dataAuth as $key => $field) {
            if (is_numeric($key)) {
                $adminField = 'id';
            } else {
                $adminField = $key;
            }
            call_user_func_array($closure, [$field, $adminField]);
        }
    }
}
